/* -*-C-*-
 ##############################################################################
 #
 # File:        trice/src/testmeas.c
 # RCS:         "@(#)$Revision: 1.18 $ $Date: 94/03/09 11:15:13 $"
 # Description: User routine for doing self test of E1430 module meas loop
 # Author:      Doug Passey
 # Created:     
 # Language:    C
 # Package:     E1430
 # Status:      "@(#)$State: Exp $"
 #
 # (C) Copyright 1992, Hewlett-Packard Company, all rights reserved.
 #
 ##############################################################################
 #
 # Please add additional comments here
 #
 # Revisions:
 #
 ##############################################################################
*/

#    include <stdio.h>
#    include <math.h>

#include "trice.h"
#include "err1430.h"

#ifndef lint
const char i1430_testmeas_fileId[] = "$Header: testmeas.c,v 1.18 94/03/09 11:15:13 chriss Exp $";
#endif


/*****************************************************************************
 *
 * This function tests the ability to control the measurement loop via
 * the Measurement Control Register.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_test_meas_control(SHORTSIZ16 la)
{
  SHORTSIZ16 i, value, error, status;
  SHORTSIZ16 reg;
  char buf1[80];
  SHORTSIZ16 groupID;

  groupID = e1430_create_module_group(1, &la);

  (void)sprintf(buf1, "%d", (LONGSIZ32)la);

  error = e1430_reset_module(groupID);
  if(error) return(error);

  /* check reset of DSP section */
  error = i1430_release_sync(la, MEAS_CONTROL_RESET_DSP_MODE);
  if(error) return(error);

  error = e1430_write_register_card(la, E1430_ZOOM_CONTROL_REG, 0x0A);
  if(error) return(error);

  error = e1430_read_register_card(la, E1430_ZOOM_CONTROL_REG, &reg);
  if(error) return(error);

  if(reg != (SHORTSIZ16)0xFF0A) {  /* make sure we can read what we wrote */
    error = i1430_Error(ERR1430_RESET_DSP, NULL, NULL);
    if(error) return(error);
  }

  error = i1430_pull_sync(la, MEAS_CONTROL_RESET_DSP_MODE);
  if(error) return(error);

  error = e1430_read_register_card(la, E1430_ZOOM_CONTROL_REG, &reg);
  if(error) return(error);

  if(reg != (SHORTSIZ16)0xFF00) {	/* make sure it reset */
    error = i1430_Error(ERR1430_RESET_DSP, NULL, NULL);
    if(error) return(error);
  }

  error = e1430_write_register_card(la, E1430_ZOOM_CONTROL_REG, 7);
  if(error) return(error);

  error = i1430_release_sync(la, MEAS_CONTROL_REG_LOAD_MODE);
  if(error) return(error);		/* load accum */

  error = i1430_pull_sync(la, MEAS_CONTROL_REG_LOAD_MODE);
  if(error) return(error);

  error = e1430_read_register_card(la, E1430_ZOOM_PHASE_1_REG, &reg);
  if(error) return(error);

  if(reg != (SHORTSIZ16)0xFF26) {	/* make sure it loaded */
    error = i1430_Error(ERR1430_RESET_DSP, NULL, NULL);
    if(error) return(error);
  }

  /* cycle thru all combinations for E1430_MEAS_CONTROL_REG */
  for(i=0; i<8; i++) {
    if((i&2)==0  || i<6) {
      error = e1430_write_register_card(la, E1430_MEAS_CONTROL_REG, i);
      if(error) return(error);

      error = e1430_get_status(la, &value);
      if(error) return(error);

      if((value & 0x008F) != 0x8C) {
        error = i1430_Error(ERR1430_INCORRECT_IDLE_EXIT, buf1, NULL);
        if(error) return(error);
      }
    }
  }


  /* do this stuff to keep module in MEAS state without collecting data:
   * set decimation to 1, later change trigger decimation to 0 to hang in
   * in MEAS state 
   */
  error = e1430_write_register_card(la, E1430_TRIGGER_PASSOUT_REG, 1);
  if(error) return(error);

  error = e1430_write_register_card(la, E1430_DATA_FORMAT_REG, 0x10);
  if(error) return(error);

  /* we are in the IDLE state here, let's step thru all the states 
   * in measurement loop
   */

  /* first disable triggering */
  error = e1430_write_register_card(la, E1430_TRIGGER_SETUP_REG,
	TRIGGER_SETUP_TRIG_AUTO_OFF | TRIGGER_SETUP_TRIG_DISABLE);
  if(error) return(error);

  error = i1430_release_sync(la, MEAS_CONTROL_NORMAL_MODE);
  if(error) return(error);

  error = i1430_pull_sync(la, MEAS_CONTROL_NORMAL_MODE); 	/* should go to ARM */
  if(error) return(error);

  error = e1430_get_status(la, &value);
  if(error) return(error);

  if((value & 0xCF8F) != 0x448D) { 	/*check for arm state , no data yet */
    error = i1430_Error(ERR1430_FAIL_ENTER_ARM, buf1, NULL);
    if(error) return(error);
  }

  error = i1430_release_sync(la, MEAS_CONTROL_NORMAL_MODE); 	/* should go to TRIG */
  if(error) return(error);
  
  error = e1430_get_status(la, &value);
  if(error) return(error);

  if((value & 0xCF8F) != 0x448F) { 	/*check for trigger state , no data */
    error = i1430_Error(ERR1430_FAIL_ENTER_TRIGGER, buf1, NULL);
    if(error) return(error);
  }

  /* do this to hang it in MEAS state without collecting data */
  error = e1430_write_register_card(la, E1430_TRIGGER_PASSOUT_REG, 0);
  if(error) return(error);

  error = i1430_pull_sync(la, MEAS_CONTROL_NORMAL_MODE); 	/* should go to MEAS */
  if(error) return(error);

  error = e1430_get_status(la, &value);
  if(error) return(error);

  if((value & 0xCF8F) != 0x408E) { 	/*check for meas state , no data */
    error = i1430_Error(ERR1430_FAIL_ENTER_MEASURE, buf1, NULL); 
    if(error) return(error);
  }

  error = i1430_release_sync(la, MEAS_CONTROL_NORMAL_MODE);
  if(error) return(error);
  
  /* enable module to collect data */
  error = e1430_write_register_card(la, E1430_TRIGGER_PASSOUT_REG, 1);
  if(error) return(error);

  error = i1430_wait_for_block_ready_la(la, &status);
  if(error) {
    if(-1 == error) {		/* device_clear from SCPI */
      (void)e1430_abort_meas(e1430_groupID);
      return(0);
    }else{
      return(error);
    }
  }

  e1430_pause(.85);

  error = e1430_get_status(la, &value);
  if(error) return(error);

  if((value & 0xCF8F) != 0x4B8C) { 	/*check for IDLE state , data */
    error = i1430_Error(ERR1430_FAIL_ENTER_IDLE, buf1, NULL);
    if(error) return(error);
  }

  /* test auto trigger */
  error = e1430_write_register_card(la, E1430_TRIGGER_SETUP_REG,
	TRIGGER_SETUP_TRIG_AUTO_ON | TRIGGER_SETUP_TRIG_ENABLE);
  if(error) return(error);

  error = i1430_pull_sync(la, MEAS_CONTROL_NORMAL_MODE); /* should go to trigger */
  if(error) return(error);
  
  error = i1430_release_sync(la, MEAS_CONTROL_NORMAL_MODE);
  if(error) return(error);
  
  error = e1430_get_status(la, &value);
  if(error) return(error);

  if((value & 0x3) == 0x3) { 	/*check for NOT in TRIGGER state */
    error = i1430_Error(ERR1430_FAIL_AUTO_TRIGGER, buf1, NULL);
    if(error) return(error);
  }

  error = e1430_delete_module_group(groupID);

  return (error);
}


/*****************************************************************************
 *
 * This function verifies the programming of the ADC and DSP clock sources
 *
 ****************************************************************************/
SHORTSIZ16 e1430_test_timing_setup(SHORTSIZ16 la)
{
  volatile SHORTSIZ16 reg; 
  SHORTSIZ16 state, error;
  char buf1[80];
  char buf2[80];

  (void)sprintf(buf1, "%d", (LONGSIZ32)la);
  
  e1430_addr = e1430_get_register_address(la, E1430_VXI_CONTROL_REG);

  E1430_TRY 

    iwpoke( (USHORTSIZ16 *)e1430_addr, 1);		/* reset module */
    iwpoke( (USHORTSIZ16 *)e1430_addr, 0);
    E1430_CHECK_BERR

  E1430_RECOVER {
    return(i1430_Error(ERR1430_NO_SOFT_RESET, buf1, NULL));
  }

  E1430_TRY		/* make sure we can read status register */

    e1430_addr = e1430_get_register_address(la, E1430_VXI_STATUS_REG);
    reg = iwpeek( (USHORTSIZ16 *)e1430_addr);
    E1430_CHECK_BERR
    e1430_cur_status = reg;

  E1430_RECOVER {
    return(i1430_Error(ERR1430_STATUS_REG_READ, buf1, NULL));
  }

  for(e1430_i=0; e1430_i<16; e1430_i++) {	/* for all combinations of timing */
    E1430_TRY

      e1430_addr = e1430_get_register_address(la, E1430_TIMING_SETUP_REG);
      iwpoke( (USHORTSIZ16 *)e1430_addr, (unsigned short)e1430_i);
      E1430_CHECK_BERR

    E1430_RECOVER {
      error = i1430_Error(ERR1430_TIMING_REG_RW, buf1, NULL);
      if(error) return(error);
    }

      e1430_pause(.020);		/* let stuff settle out */

      e1430_addr = e1430_get_register_address(la, E1430_MEAS_CONTROL_REG);

    E1430_TRY /* write to MEAS_CONTROL_REG will bus error without DSP clock */


      iwpoke((USHORTSIZ16 *)e1430_addr, 
	MEAS_CONTROL_IDLE_MODE | MEAS_CONTROL_SYNC_ON);  /* idle */
  
      E1430_CHECK_BERR
      iwpoke((USHORTSIZ16 *)e1430_addr, 
	MEAS_CONTROL_IDLE_MODE | MEAS_CONTROL_SYNC_ON);

      iwpoke((USHORTSIZ16 *)e1430_addr, 
	MEAS_CONTROL_NORMAL_MODE | MEAS_CONTROL_SYNC_OFF);  /* arm */

      iwpoke((USHORTSIZ16 *)e1430_addr, 
	MEAS_CONTROL_NORMAL_MODE | MEAS_CONTROL_SYNC_ON);	

      iwpoke((USHORTSIZ16 *)e1430_addr, 
	MEAS_CONTROL_NORMAL_MODE | MEAS_CONTROL_SYNC_OFF);/* trigger*/

      iwpoke((USHORTSIZ16 *)e1430_addr, 
	MEAS_CONTROL_NORMAL_MODE | MEAS_CONTROL_SYNC_ON);	
      E1430_CHECK_BERR
 
      switch (e1430_i) {
	case 1:		/* multi_sync, DSP from ADC clock */
	case 4:		/* ext ADC, DSP from ADC clock */
	case 5:
	case 6:
	case 7:
	  (void)sprintf(buf2, "%d", (LONGSIZ32)e1430_i);
          error = i1430_Error(ERR1430_IMPROPER_DSP_CLOCK, buf1, buf2);
          if(error) return(error);
	  break;

	default:
	  break;
      }
      
      e1430_addr = e1430_get_register_address(la, E1430_VXI_STATUS_REG);
      reg = iwpeek((USHORTSIZ16 *)e1430_addr);
      E1430_CHECK_BERR
      e1430_cur_status = reg;

      state = reg & E1430_MEAS_STATUS_STATE_MASK;

      /* SYNC line goes low to advance to MEAS state ONLY if ADC clock is
       * present.  Check for advance to MEAS state for the cases where
       * there should be an ADC clock.
       */
      switch(e1430_i) {
	case 0:			/* int ADC, DSP from ADC */
	case 2:			/* int ADC, DSP from ADC, master */
	case 3:			/* int ADC, DSP from ADC, multi-sync, master */
	case 8:			/* int DSP, int ADC clock */
	case 10:		/* int DSP, int ADC, master */
	case 11:		/* int DSP, multi_sync, master */
	  if(state != E1430_MEAS_STATUS_MEAS_STATE) {
	    (void)sprintf(buf2, "%d", (LONGSIZ32)e1430_i);
            error = i1430_Error(ERR1430_MISSING_ADC_CLOCK, buf1, buf2);
            if(error) return(error);
	  }
	  break;

	/* check cases where no advance to MEAS state (i.e. no SYNC_LOW
	 * should occur).
	 */
	case 9:			/* int DSP, multi_sync */
	case 12:		/* ext ADC, int DSP clock */
	case 13:
	case 14:
	case 15:
	  if(state != E1430_MEAS_STATUS_IDLE_STATE) {
	    (void)sprintf(buf2, "%d", (LONGSIZ32)e1430_i);
            error = i1430_Error(ERR1430_IMPROPER_ADC_CLOCK, buf1, buf2);
            if(error) return(error);
	  }
	  break;
	default:
	  break;
      }
      
    E1430_RECOVER {	/* from attempt to write to MEAS_CONTROL_REG with
			   no DSP clock present */
      switch(e1430_i) {
	case 0:			/* int ADC, DSP from ADC */
	case 2:			/* int ADC, DSP from ADC, master */
	case 3:			/* int ADC, DSP from ADC, multi-sync, master */
	case 8:			/* int DSP clock */
	case 9:
	case 10:
	case 11:
	case 12:
	case 13:
	case 14:
	case 15:
	  (void)sprintf(buf2, "%d", (LONGSIZ32)e1430_i);
          error = i1430_Error(ERR1430_MISSING_DSP_CLOCK, buf1, buf2);
          if(error) return(error);
	  break;
	default:
	  break;
      }
    }	/* E1430_RECOVER */
  }	/* for 0 <= e1430_i < 16 */

  return (0);



   
}


#define NUM_ADC1_BITS		9
#define NUM_OVERLAP_BITS	4
/*****************************************************************************
 *
 * Get DAC error bits.  
 *
 ****************************************************************************/
SHORTSIZ16 e1430_get_dac_error(SHORTSIZ16 la, FLOATSIZ64 *dac1, FLOATSIZ64 *dac2,
				FLOATSIZ64 *dac3, FLOATSIZ64 *gain)
{
  aModuleImage image;
  SHORTSIZ16 error, status;
  SHORTSIZ16 index, i;
  FLOATSIZ64 gainScale, dacScale;
  union {
    LONGSIZ32 int32;
    struct {
      SHORTSIZ16 hi;
      SHORTSIZ16 lo;
    } int16;
  } data;

  gainScale = 1.0 / (FLOATSIZ64)(1L << (30 - NUM_ADC1_BITS + NUM_OVERLAP_BITS));
  gainScale /= KESTREL_FACTOR;

  dacScale = 1.0 / (FLOATSIZ64)(1L << (32 - NUM_ADC1_BITS));
  dacScale /= KESTREL_FACTOR;

  error = i1430_get_index_from_la(la, &index);
  if(error) return(error);

  image = e1430_modStates[index];		/* save current state */

  error = e1430_write_register_image(la, E1430_DATA_FORMAT_REG,
	DATA_FORMAT_BLOCK_MODE_ON | DATA_FORMAT_DATA_TYPE_REAL |
	  DATA_FORMAT_DATA_SIZE_32);
  if(error) return(error);

  for(i=1; i<30; i++) {		/* cycle thru all ADCDIAG error readouts */
    error = e1430_write_register_image(la, E1430_ADC_CONTROL_REG,
					i + ADC_CONTROL_CAL_MODE_NORMAL);
    if(error) return(error);

    error = i1430_pull_sync(la, MEAS_CONTROL_IDLE_MODE);
    if(error) return(error);

    error = i1430_pull_sync(la, MEAS_CONTROL_IDLE_MODE);
    if(error) return(error);

    error = i1430_release_sync(la, MEAS_CONTROL_NORMAL_MODE);
    if(error) return(error);

    error = i1430_pull_sync(la, MEAS_CONTROL_NORMAL_MODE);	/* arm */
    if(error) return(error);

    error = i1430_release_sync(la, MEAS_CONTROL_NORMAL_MODE);  /* trigger */
    if(error) return(error);

    error = i1430_wait_for_block_ready_la(la, &status);
    if(error) {
      if(-1 == error) {		/* device_clear from SCPI */
        (void)e1430_abort_meas(e1430_groupID);
        return(0);
      }else{
        return(error);
      }
    }
 
    error = e1430_read_register_card(la, E1430_HP_SEND_DATA_REG, &data.int16.hi);
    if(error) return(error);
    
    error = e1430_read_register_card(la, E1430_HP_SEND_DATA_REG, &data.int16.lo);
    if(error) return(error);
    
    if(i==29) {				/* gain data */
      *gain = ((FLOATSIZ64)data.int32) * gainScale;
    }else if(i > 19)  {			/* dac1 data */
      dac1[i-20] = ((FLOATSIZ32)data.int32) * dacScale;
    }else if(i > 9)   {			/* dac2 data */
      dac2[i-10] = ((FLOATSIZ32)data.int32) * dacScale;
    }else{				/* dac3 data */
      dac3[i-1] = ((FLOATSIZ32)data.int32) * dacScale;
    }
    
  }

  error = i1430_restore_state_la(la, &image);
  if(error) return(error);

  return 0;
}
